#include "host_run_one_iteration.h"
#include "ap_int.h"
prop_t *vertexScore_buffer[2];
void runoneiteration_init(graphInfo *info)
{
	printf("runoneiteration_init started\n");

	int *edgesTuples  = (int*)get_host_mem_pointer(MEM_ID_EDGE_TUPLES);
	int *edgeScoreMap = (int*)get_host_mem_pointer(MEM_ID_EDGE_SCORE_MAP);
	int *edgeProp     = (int*)get_host_mem_pointer(MEM_ID_EDGE_PROP);

	prop_t *vertexScoreMapped   = (prop_t*)get_host_mem_pointer(MEM_ID_VERTEX_SCORE_MAPPED);

	vertexScore_buffer[0]=new prop_t[info->vertexNum]();
	vertexScore_buffer[1]=new prop_t[info->vertexNum]();
	memcpy(vertexScore_buffer[0],vertexScoreMapped,info->vertexNum*sizeof(prop_t));

	graphAccelerator * acc = getAccelerator();
	int blkNum = info->blkNum;
	for (int i = 0; i < blkNum + 1; i ++)
	{
		if (i < blkNum)
		{
			for (int j = 0; j < SUB_PARTITION_NUM; j++)
			{
		    	subPartitionDescriptor * partition = getSubPartition(getArrangedPartitionID(i) * SUB_PARTITION_NUM + j);
		       	unsigned int *map=(unsigned int*)partition->edgeMap.data;
		       	unsigned int *edge=(unsigned int*)partition->edge.data;
		       	unsigned int *edge1=(unsigned int*)partition->edge1.data;
		       	unsigned int *edge2=(unsigned int*)partition->edge2.data;
		       	unsigned int *edge3=(unsigned int*)partition->edge3.data;
		       	unsigned int *edge4=(unsigned int*)partition->edge4.data;
		       	/*for(int k=0;k<partition->listEnd;k+=64){
		       		for(int kk=0;kk<16;kk++)
		       			edge1[k/4+kk]=edge[k+0*16+kk];
		       		for(int kk=0;kk<16;kk++)
		       			edge2[k/4+kk]=edge[k+1*16+kk];
		       		for(int kk=0;kk<16;kk++)
		       			edge3[k/4+kk]=edge[k+2*16+kk];
		       		for(int kk=0;kk<16;kk++)
		       			edge4[k/4+kk]=edge[k+3*16+kk];
		       	}*/
			for(int k=0;k<partition->listEnd;k+=4*512){
                                for(int kk=0;kk<512;kk++)
                                        edge1[k/4+kk]=edge[k+0*512+kk];
                                for(int kk=0;kk<512;kk++)
                                        edge2[k/4+kk]=edge[k+1*512+kk];
                                for(int kk=0;kk<512;kk++)
                                        edge3[k/4+kk]=edge[k+2*512+kk];
                                for(int kk=0;kk<512;kk++)
                                        edge4[k/4+kk]=edge[k+3*512+kk];
                        }


		       	{
		       		int num=(32*1024*1024+4096);
		       		int *tmp_csrIndex=new int[2*num];
		       		for(int k=0;k<2*num;k++){
		       			tmp_csrIndex[k]=-1;
		       		}
		       		tmp_csrIndex[0]=0;
		       		for(int k=0;k<partition->listEnd;k++){
		       			if(edge[k]!=(ENDFLAG-1))
		       				tmp_csrIndex[2*(map[k]/1)+1]=k+1;
		       			//if(k>=6272&&k<6272+32) printf("map[%d]=%d\n",k,map[k]);
		       		}
		       		for(int k=0;k<2*num;k++){
		       			if(tmp_csrIndex[k]==-1)
		       				tmp_csrIndex[k]=tmp_csrIndex[k-1];
		       		}


		       		int *csrIndex=(int *)partition->csrIndex.data;
		       		int *csrIndex1=(int *)partition->csrIndex1.data;
		       		int *csrIndex2=(int *)partition->csrIndex2.data;
		       		//int *csrIndex3=(int *)partition->csrIndex3.data;
		       		//int *csrIndex4=(int *)partition->csrIndex4.data;
		       		for(int k=0;k<num;k+=16){
		       			ap_uint<512> block=0;
		       			for(int kk=0;kk<16;kk++){
		       				block.range(30*kk+29,30*kk)=tmp_csrIndex[2*(k+kk)];
		       			}
		       			block.range(30*16+29,30*16)=tmp_csrIndex[2*(k+15)+1];
		       			for(int kk=0;kk<16;kk++){
		       				csrIndex[(k+kk)]=block.range(32*kk+31,32*kk);
		       			}
		       		}
		       		/*for(int k=0;k<num;k+=4*512){
		       			for(int kk=0;kk<512;kk++){
		       				csrIndex1[(k/4+kk)]=csrIndex[(k+0*512+kk)];
		       				csrIndex2[(k/4+kk)]=csrIndex[(k+1*512+kk)];
		       				csrIndex3[(k/4+kk)]=csrIndex[(k+2*512+kk)];
		       				csrIndex4[(k/4+kk)]=csrIndex[(k+3*512+kk)];
		       			}
		       		}*/
		       		for(int k=0;k<(num);k+=2*512){
		       			for(int kk=0;kk<512;kk++){
		       				csrIndex1[(k/2+kk)]=csrIndex[(k+0*512+kk)];
		       				csrIndex2[(k/2+kk)]=csrIndex[(k+1*512+kk)];
		       			}
		       		}

		       		if(0){
		       			for(int k=0;k<info->vertexNum;k++){
		       				printf("csrIndex %d:%x~%x\n",k,csrIndex2[k],csrIndex2[k+1]);
		       			}
		       		}
		       		//exit(1);
		       	}
		       	{

		       	}



		    	int id_array[7];
		     	id_array[0]=(int)partition->edge1.id;
		     	id_array[1]=(int)partition->edge2.id;
		     	id_array[2]=(int)partition->edge3.id;
		     	id_array[3]=(int)partition->edge4.id;
		     	id_array[4]=(int)partition->csrIndex1.id;
		     	id_array[5]=(int)partition->csrIndex2.id;
		     	//id_array[6]=(int)partition->csrIndex3.id;
		     	//id_array[7]=(int)partition->csrIndex4.id;
		        transfer_data_to_pl(acc->context, acc->device,id_array, 7);
			}
		}
	}

	printf("runoneiteration_init finished\n");
}

bool runoneiteration(graphInfo *info,int runCounter)
{
	printf("runoneiteration started\n");

	prop_t *vertex_beifen=new prop_t[info->vertexNum];
	memcpy(vertex_beifen,vertexScore_buffer[runCounter % 2],info->vertexNum*sizeof(prop_t));
	if(1){
			prop_t *vertex_ori=vertexScore_buffer[runCounter%2];
			for(int k=0;k<info->vertexNum;k++){
				if(vertex_ori[k]!=(((prop_t)runCounter+1)|0x80000000)){
					vertex_ori[k]&=(0x80000000-1);
				}
			}
	}

	graphAccelerator * acc = getAccelerator();
	for (int i = 0; i < SUB_PARTITION_NUM; i++){
		gatherScatterDescriptor * gsHandler = getGatherScatter(i);
		prop_t *krnl_vertex_data=(prop_t *)get_host_mem_pointer(gsHandler->prop[0 % 2].id);
		memcpy(krnl_vertex_data,vertexScore_buffer[runCounter % 2],info->vertexNum*sizeof(prop_t));

		int *bitMap=(int *)gsHandler->bitMap.data;
		prop_t *vertex_ori=vertexScore_buffer[runCounter%2];
		for(int k=0;k<((info->vertexNum%32)?((info->vertexNum/32)+1):(info->vertexNum/32));k++){
			bitMap[k]=0;
		}
		for(int k=0;k<info->vertexNum;k++){
			if(vertex_ori[k]==(((prop_t)runCounter+1)|0x80000000)){
				bitMap[k/32]|=1<<(k%32);
			}
		}
		if(0){
			for(int k=0;k<((info->vertexNum%32)?((info->vertexNum/32)+1):(info->vertexNum/32));k++){
				printf("bitMap %d~%d:%x\n",32*k,32*k+31,bitMap[k]);
			}
		}

		int id_array[2];
		id_array[0]=(int)gsHandler->prop[0 % 2].id;
		id_array[1]=(int)gsHandler->bitMap.id;
		transfer_data_to_pl(acc->context, acc->device,id_array, 2);
	}

	if(1)
	{
		prop_t *vertexScoreMapped   = (prop_t*)get_host_mem_pointer(MEM_ID_VERTEX_SCORE_MAPPED);
		memcpy(vertexScoreMapped,vertexScore_buffer[runCounter % 2],info->vertexNum*sizeof(prop_t));
		int id_array[1];
		id_array[0]=MEM_ID_VERTEX_SCORE_MAPPED;
		transfer_data_to_pl(acc->context, acc->device,id_array, 1);
	}


	memcpy(vertexScore_buffer[runCounter % 2],vertex_beifen,info->vertexNum*sizeof(prop_t));

	//printf("iter %d:start\n",runCounter);

	int *edgesTuples  = (int*)get_host_mem_pointer(MEM_ID_EDGE_TUPLES);
	int *edgeScoreMap = (int*)get_host_mem_pointer(MEM_ID_EDGE_SCORE_MAP);
	int *edgeProp     = (int*)get_host_mem_pointer(MEM_ID_EDGE_PROP);

	prop_t *vertex_ori=vertexScore_buffer[runCounter%2];
	prop_t *vertex_update=vertexScore_buffer[(runCounter+1)%2];
	memcpy(vertex_update,vertex_ori,info->vertexNum*sizeof(prop_t));

	for(int j=0;j<info->edgeNum;j++){
		if(edgesTuples[j]==(ENDFLAG - 1)){
			continue;
		}
		int address=edgesTuples[j];
		prop_t update=vertex_ori[edgeScoreMap[j]];
		if(IS_ACTIVE_VERTEX(update)){
			int old_val=vertex_update[address];
			vertex_update[address]=PROP_COMPUTE_STAGE4(vertex_update[address],update+1);
			//printf("vertex %d:from %x to %x\n",address,old_val,vertex_update[address]);
		}
	}
	int diff=0;
	int nozero_count=0;
	for(int i=0;i<info->vertexNum;i++){
		if(vertex_ori[i]!=vertex_update[i]){
			diff++;
		}
		if(IS_ACTIVE_VERTEX(vertex_update[i])){
			nozero_count++;
		}
		if(i==193989){
			printf("vertex %d:from %x to %x\n",i,vertex_ori[i],vertex_update[i]);
		}
	}
	printf("iter %d:new update %d,total %d\n",runCounter,diff,nozero_count);
	if(diff) return false;
	else return true;
}
